Skip to content

Conversation

@ChengHauYang
Copy link
Member

@ChengHauYang ChengHauYang commented Oct 21, 2025

Motivation

Currently, libMesh assumes physical continuity (base on node ID) between neighboring elements, which limits its ability to handle cases where two regions share coincident boundaries but are geometrically disconnected -- for instance, across interfaces with discontinuous fields or temperature jumps.
This PR introduces a mechanism to explicitly register disconnected boundary pairs, enabling the framework to reconstruct logical neighbor relationships even when elements are not directly connected in the mesh topology (base on node ID).
This functionality is particularly relevant for methods such as the Cohesive Zone Method (CZM), where field continuity is enforced weakly across interfaces.

This work is motivated by long-standing MOOSE discussions about “fake” or “pseudo” neighbors -- element pairs that were once topological neighbors but become disconnected due to node replacement (e.g., in BreakMeshByBlockGenerator).
See the following issues for historical context:

  • MOOSE #12033: Support for non-geometric neighbor connections -- initial proposal to allow interface coupling between geometrically separated regions.
  • MOOSE #21161: BreakMeshByBlock connectivity -- highlighted that after node replacement, elements that were formerly neighbors lose topological connectivity, motivating the need for a libMesh-level mechanism to handle such cases.

This PR effectively formalizes that capability at the libMesh level, turning what was previously a MOOSE-side workaround into a supported feature.

Design

  1. Disconnected Boundary Framework: Introduced an API in MeshBase (add_disconnected_boundaries() and get_disconnected_boundaries()) that allows users to register and access disconnected boundary pairs. These pairs are stored as PeriodicBoundaries objects and used during neighbor search to establish logical connections between geometrically separated regions.
  2. Neighbor Reconstruction and Validation: Extended UnstructuredMesh::find_neighbors() to detect and link virtual (fake, or disconnected) neighbors across disconnected interfaces (boundaries). A new regression test (disconnected_neighbor_test.C) verifies correct neighbor mapping and demonstrates a temperature-jump interface problem that matches the analytical solution.

Impact

Facilitates coupling between subdomains separated by non-matching meshes or duplicated boundaries.

Copy link
Member

@roystgnr roystgnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this, in principle, and the MOOSE test failures should be trivial to fix. Hopefully the distributed unit test sweep failures won't be much harder.

@ChengHauYang ChengHauYang force-pushed the break_mesh_libmesh_pr branch from e5f64ed to 120b7c1 Compare October 21, 2025 19:37
@roystgnr
Copy link
Member

Do we have discussion of the problem motivating this anywhere on Github that we can link to, for future reference? I know there's been multiple discussions of the "MOOSE can abuse neighbor pointers" issue somewhere, but I can't recall whether any were here rather than on Slack or over video.

I'm not sure how relevant the discussions would be, because IIRC in most of them my opinion had been "we should come up with a different mechanism for MOOSE to use instead of neighbor_ptr" and I think you've managed to convert me to "we should make it so that misuse of neighbor_ptr is actually a supported use", but it'd still be good to be able to look up the history.

@roystgnr
Copy link
Member

Ooh. One thing I missed in the review: this has a good chance of failing in interesting ways as soon as we use it in the presence of refined elements on either side of the pseudo-neighbor links, doesn't it? And we don't have any coverage of that, do we? We need another unit test or two; it'd probably be adequate to just refactor your existing test but refine both elements in the second test and refine just one element in the third.

@ChengHauYang
Copy link
Member Author

Thank you, @roystgnr ! I tried to add MOOSE #12033 and MOOSE #21161 to the Motivation section of the PR so that others can easily look up the historical context.

@roystgnr
Copy link
Member

Gah, I forgot to re-activate CI for you. Sorry! I'm going to have you sent an Associates team invite so any future pushes can auto-activate CI.

@roystgnr
Copy link
Member

Jobs manually activated, hopefully the last time that's necessary; let me know if the invite doesn't get to you or gives you any problems.

@roystgnr
Copy link
Member

I'm also adding a few optional recipes that I'm not 100% sure will pass; I don't want to merge if this passes here only to find we have to fix something up for our devel->master merges.

Copy link
Member

@roystgnr roystgnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only definite fix we need is for that random whitespace futzing that got left around.

Oh, but we might also need to #ifdef LIBMESH_HAVE_SOLVER around those tests, since they involve a solve(); I'm not sure any of our regular recipes use such a decimated libMesh, but better safe than sorry.

@ChengHauYang ChengHauYang force-pushed the break_mesh_libmesh_pr branch from 99faccb to 64e4597 Compare October 24, 2025 15:48
@roystgnr
Copy link
Member

Well, the good news is that the invite went through and CI is autorunning now. The bad news is that we're failing multiple recipes. "Test mac" is a red herring, but the distributed-mesh test looks like a real failure and I can't even imagine what is going on in the --disable-amr and --disable-deprecated tests.

@ChengHauYang
Copy link
Member Author

Thank you, Roy, for your feedback. I think this issue is related to whether disconnected elements are being added as ghosted elements. I recently implemented a RelationshipManager in MOOSE, which allows me to properly handle disconnected neighbors on distributed meshes. However, this functionality is not yet available on the libMesh side. I plan to add a GhostingFunctor for disconnected neighbors in libMesh to see if that resolves the issue. Thanks again for taking the time to look into this.

@moosebuild
Copy link

moosebuild commented Oct 25, 2025

Job Coverage, step Generate coverage on 7756815 wanted to post the following:

Coverage

a6c92c #4283 775681
Total Total +/- New
Rate 65.13% 65.18% +0.05% 86.50%
Hits 77157 77300 +143 141
Misses 41309 41296 -13 22

Diff coverage report

Full coverage report

Warnings

  • New new line coverage rate 86.50% is less than the suggested 90.0%

This comment will be updated on new commits.

@ChengHauYang ChengHauYang force-pushed the break_mesh_libmesh_pr branch 6 times, most recently from a7b9cfb to 71680c0 Compare October 28, 2025 22:06
@ChengHauYang
Copy link
Member Author

Dear @roystgnr ,

Thank you for your guidance. I’ve fixed the bugs related to distributed meshes, as well as those occurring when using --disabled-amr or --disabled-deprecated.

Here’s a brief summary of my recent changes:

  1. Implemented a new GhostFunctor that utilizes point_locator and disconnected boundary pairs to add disconnected elements as ghost elements. This resolves the errors associated with distributed meshes.
  2. Fixed a bug where internal boundaries could produce invalid side IDs when calling side_with_boundary_id under --disabled-amr. A corresponding unit test was added for verification.
  3. Added three unit tests for disconnected neighbor handling and resolved test failures triggered by --disabled-deprecated. The previous failures occurred because fe->reinit(...) was called before fe->get_phi().

All tests are now passing. Could you please provide your feedback and review when you have a chance?

Thanks again!

@roystgnr
Copy link
Member

roystgnr commented Nov 3, 2025

I think that set of OverlappingCouplingGhostingTest failures in the Test No AMR recipe is a bug of mine; rebasing on devel again should fix it. But this:

3) test: DisconnectedNeighborTest::testTempJumpLocalRefineFail (F) 
expected exception not thrown

is from this PR - you'll want to disable that test when LIBMESH_ENABLE_AMR isn't defined.

Review to follow.

…n also access them.

(b) add geometry-based detection of disconnected neighbors via paired boundaries
- Introduced `Elem::geometrically_equal()` for tolerance-based geometric comparison of elements.
- Replaced `_has_disconnected_neighbor` with `_boundary_id_pairs` for boundary-pair registration.
- Updated `UnstructuredMesh::find_neighbors()` to auto-detect disconnected neighbors using geometric matching and paired boundaries.
- Introduced PeriodicBoundaries::disconnected_neighbor() to locate geometrically coincident elements across disconnected boundaries using PointLocator.
- Replaced legacy geometry-based neighbor search in UnstructuredMesh::find_neighbors() with unified PeriodicBoundaries-based logic.
- Moved new MeshBase functions out of the header to use forward declarations, reducing unnecessary includes.
- Reverted the PeriodicBoundaries::neighbor() logic to allow self-matching, since the existing boundary ID check already prevents unintended self-detections in periodic boundary cases.
(a) Revert periodic BC source file
(b) Fix indentation in UnstructuredMesh::find_neighbors and wrap tests (c) involving solve() in DisconnectedNeighborTest with #ifdef LIBMESH_HAVE_SOLVER guards to ensure correct conditional compilation.
@ChengHauYang ChengHauYang force-pushed the break_mesh_libmesh_pr branch from f956256 to 38787d8 Compare November 3, 2025 18:22
@ChengHauYang
Copy link
Member Author

Thank you, @roystgnr, for your carefully checking. I just fixed that test and rebased the code again.

Copy link
Member

@roystgnr roystgnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the "oh, whoops, why didn't I notice that before" change requests, when previously it had seemed we were a hair's breadth away from being done. Clearly my reviews need reviews.

@ChengHauYang ChengHauYang force-pushed the break_mesh_libmesh_pr branch 2 times, most recently from 8271f2d to 9857539 Compare November 3, 2025 22:20
Refactored the ghosting workflow following @roystgnr’s review.
Removed the separate DisconnectedNeighborCoupling class and integrated its logic directly into GhostPointNeighbors for a cleaner and more consistent approach.
This avoids duplicate functor additions in `UnstructuredMesh::find_neighbors`.

- Deleted `DisconnectedNeighborCoupling.[C,h]` and updated Makefiles
- Moved all related logic into `GhostPointNeighbors::operator()`
- Added move assignment and equality checks for `_disconnected_boundary_pairs` in `MeshBase`. This was a great catch from Roy and is needed for mesh cloning/comparisons to work correctly.
- Added `libmesh_deprecated()` warning to `UnstructuredMesh::stitching_helper` for disconnected meshes
- Replaced a `libmesh_error_msg` in `MeshRefinement` with `libmesh_not_implemented_msg`
- Updated unit tests: added `LOG_UNIT_TEST` for `disconnected_neighbor_test`
@ChengHauYang ChengHauYang force-pushed the break_mesh_libmesh_pr branch from 9857539 to d100e50 Compare November 4, 2025 00:55
Copy link
Member

@roystgnr roystgnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting closer, at least!

With subsequent changes, could you append commits rather than force-pushing them? It is literally asymptotically faster to re-review when I only need to look at new changes rather than all changes.

…nment

- Added deep copy logic for `_disconnected_boundary_pairs` in both the
  copy constructor and move assignment operator of `MeshBase`, ensuring
  that `clone()` preserves disconnected boundary data.
- Updated `locally_equals()` to perform a safer weak comparison on
  `_disconnected_boundary_pairs` (compare sizes only).
- Added `DisconnectedNeighborTest::testCloneEquality()` to verify that
  cloned meshes correctly replicate disconnected boundaries.
Copy link
Member

@roystgnr roystgnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to give @jwpeterson a chance to look at this too before merging, but I think this is ready to go so unless John or CI scream at us we'll merge tomorrow.

I'm going to add a bunch of the devel->master recipes to this PR first, too, though, just to make sure I'm not missing anything that we might get hung up on after merging.

@roystgnr
Copy link
Member

roystgnr commented Nov 4, 2025

This was kind of a brutal review process; sorry! Thanks for pushing through it with me! Though, honestly, even after all that this is a much less massive change than I'd have expected it to become. We are still at the most basic stages if we're not supporting stitching or refinement yet, but I wouldn't have expected even the most basic support to be possible with only ~400 lines of library code. I've still got a "waiting for the other shoe to drop" feeling, and I won't be too surprised if trying to use this in MOOSE this brings up some unpleasant surprises, but with ~600 lines of tests hopefully we've preempted anything too nasty.

@ChengHauYang
Copy link
Member Author

Thank you, @roystgnr, for providing me with much constructive feedback during this process! Really appreciate your guidance!

@hugary1995
Copy link
Contributor

We should probably test idaholab/moose#31636 against this PR branch and make sure it's green.

@jwpeterson
Copy link
Member

I want to give @jwpeterson a chance to look at this too before merging,

It sounds like you've already reviewed it pretty thoroughly so 👍 from me.

@hugary1995
Copy link
Contributor

I think it'll be a pain to enable CI for idaholab/moose#31636 for @ChengHauYang with a libmesh submodule update. Let's just go ahead and merge this first, and we can wait for the next libmesh update in moose.

@ChengHauYang can you confirm that your changes on the moose side are compatible with this libmesh PR branch? I would like to make sure tests related to BreakMeshByBlockGenerator are passing (or can be easily adapted).

…in UnstructuredMesh

This commit enables stitching of meshes that include disconnected boundaries, allowing MOOSE tests using `BreakMeshByBlock` (bmbb) to run successfully with `StitchBoundaryMeshGenerator`.

- Added `stitching_intended_disconnected_neighbors` option to stitching_helper().
- Implemented logic to detect and handle valid disconnected boundary pairs from either mesh, supporting self-stitching and multi-mesh stitching cases.
- Added `remove_disconnected_boundaries_pair()` to MeshBase to clean up boundary pairs after stitching.
- Added a new unit test `testStitchingDiscontinuousBoundaries()` to verify the correct behavior of disconnected boundary stitching.
@ChengHauYang
Copy link
Member Author

ChengHauYang commented Nov 6, 2025

Hi @hugary1995 ,

I’ve removed most instances of mesh_mode = 'replicated' in the test files and reran the following tests:

MOOSE core tests

./run_tests --re=break_mesh_by_block_generator --distributed-mesh -j 8
./run_tests --re=break_mesh_by_block_generator -j 8

./run_tests --re=interface_material --distributed-mesh -j 8
./run_tests --re=interface_material -j 8

./run_tests --re=equal_value_boundary_constraint --distributed-mesh -j 8
./run_tests --re=equal_value_boundary_constraint -j 8

./run_tests --re=no_failed_point_inversions --distributed-mesh -j 8
./run_tests --re=no_failed_point_inversions -j 8

Solid Mechanics module

./run_tests --re=cohesive_zone_model --distributed-mesh -j 8
./run_tests --re=cohesive_zone_model -j 8

Heat Transfer module

./run_tests --re=thin_layer_heat_transfer --distributed-mesh -j 8
./run_tests --re=thin_layer_heat_transfer -j 8

Contact module

./run_tests --re=cohesive_zone_model --distributed-mesh -j 8
./run_tests --re=cohesive_zone_model -j 8

Combined module

./run_tests --re=break_mesh_interface_contact --distributed-mesh -j 8
./run_tests --re=break_mesh_interface_contact -j 8

All tests above now pass successfully in both replicated and distributed modes.

However, one test (stitch_boundary_mesh_generator) still fails, since stitching after BreakMeshByBlock doesn’t yet handle disconnected neighbors. I’ve started modifying stitching_helper to add support for this case. The changes help fix broken tests related to stitching in MOOSE.

@roystgnr, could you please review this section of the code in my latest commit (8fb68ab)? I really appreciate your help!

@roystgnr
Copy link
Member

roystgnr commented Nov 6, 2025

That "No MPI/No PETSc" failure looks like a false positive here, something brought on by #4300

@roystgnr roystgnr mentioned this pull request Nov 6, 2025
{
account_for_disconnected_boundaries = true;

// In most cases, other_mesh is nullptr (i.e., stitching the mesh to itself).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is true

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the misleading sentence about other_mesh usually being nullptr. stitching_helper is used both for "self-stitching" and for "stitching two meshes"; I shouldn’t imply a typical case here.

MeshTools::libmesh_assert_valid_neighbors(*this);
#endif

// Determine whether to activate disconnected boundary stitching:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ambiguous. Does "disconnected boundary stitching" mean stitching across disconnected boundaries within a mesh? Preservation of disconnected boundaries from input meshes? From context I'd have assumed the latter but the phrase sounds like the former.

Copy link
Member Author

@ChengHauYang ChengHauYang Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have already renamed the "disconnected" boundary to be the "disjoint neighbor" boundary. It is clearer now.
What I want to do here is to determine whether we want to stitch the "disjoint neighbor" boundary.


#ifdef LIBMESH_ENABLE_PERIODIC
if (account_for_disconnected_boundaries)
this->remove_disconnected_boundaries_pair(this_mesh_boundary_id, other_mesh_boundary_id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so we're just handling the case where we have a disconnected_boundaries pair and we're trying to stitch across it. That leaves me with questions:

When would that ever occur with one side of the pair in this and the other in other_mesh? Shouldn't this already be pairing with itself and vice-versa?

What happens if other_mesh has disconnected_boundaries pairs? We don't seem to be copying them - are we just throwing them away? That's the sort of bug we've had to fix repeatedly, e.g. in #2850, and that's actually what I thought we needed to start supporting here; I foolishly hadn't considered the (in hindsight quite reasonable) case where we had a disconnected boundary pair and wanted to connect it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! That’s exactly right.

After rethinking this, the current implementation assumes that both sides of each disconnected boundary pair are always defined "within the same mesh". Therefore, the stitching logic only handles the self-stitching case, stitching elements across the registered disconnected boundary pairs "within a single mesh".

Cross-mesh disconnected stitching is not supported by design. This keeps the logic simpler and consistent with the concept of disconnected_boundaries, which represent internal connectivity information within one mesh rather than between meshes.

If other_mesh also needs to stitch its own disconnected boundary pairs, the user can simply call other_mesh->stitching_helper() separately. We would not take care of this here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still wrong, though, if it's not copying disconnected boundary pairs from a distinct other_mesh to this. We need to libmesh_not_implemented_msg() in that case in the very least, but I don't think adding the copy (and a test for it, for that matter) would be hard. Ideally we'd want to sanity check as we go (if a and b also exist as boundary ids on this, we should be screaming and dying, not adding neighbor pointers between them) too.

Right now, it looks to me like, if we stitch other_mesh X with disconnected boundary pair a,b into this mesh Y!=X, then we just silently drop the PeriodicBoundary objects for a,b. We can't drop mesh features when we're stitching them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A unit test here would probably only take 4 elements in a row - elements 1 and 2 with a disconnected boundary in between them, elements 3 and 4 likewise, then stitch the other side of 2 to the other side of 3, and make sure that both the 1-2 and the 3-4 pairing still exist afterward.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, on the sanity checking: if a and b already exist on this we should be screaming and dying unless they already have PeriodicBoundary objects connecting them too. It could be useful to users to be able to extend a boundary pair via the mesh they're stitching in.

Copy link
Member Author

@ChengHauYang ChengHauYang Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it's not copying disconnected boundary pairs from a distinct other_mesh to this. We need to libmesh_not_implemented_msg() in that case in the very least, but I don't think adding the copy (and a test for it, for that matter) would be hard.

I have already copy disjoint neighbor boundary pairs from other_mesh to this in the newest implementation.

Actually, on the sanity checking: if a and b already exist on this we should be screaming and dying unless they already have PeriodicBoundary objects connecting them too.

Yes. Right now I have that implementation in the newest commit: duplicates are skipped, mismatches raise errors.

A unit test here would probably only take 4 elements in a row - elements 1 and 2 with a disconnected boundary in between them, elements 3 and 4 likewise, then stitch the other side of 2 to the other side of 3, and make sure that both the 1-2 and the 3-4 pairing still exist afterward.

I added two unit tests for this:
(a) One is this mesh X has four disjoint elements (other mesh Y is nullptr). After stitching elem2 and elem3, check whether 1-2 and the 3-4 pairing still exist.
(b) X has two disjoint elements and Y has two disjoint elements. After stitching elem2 and elem3, check whether 1-2 and the 3-4 pairing still exist.

…ment

- Removed the unused argument `stitching_intended_disconnected_neighbors` from
  `UnstructuredMesh::stitching_helper()`. The disconnected boundary stitching
  is now always determined internally based on registered boundary pairs.
- Clarified logic and comments to emphasize that both sides of each
  disconnected boundary pair exist within the same mesh (`this`), and only
  self-stitching is supported by design.
- Renamed variable `account_for_disconnected_boundaries` to
  `enable_disc_bdys_stitching` for clarity.
- Updated helper lambda in `MeshBase::remove_disconnected_boundaries_pair()` to
  avoid unnecessary capture and make parameters explicit.
- Initialize `enable_disc_bdys_stitching` as false by default and enable it
  only when the specified boundary IDs form a valid disconnected pair.
- Simplify and clarify side filtering logic during stitching:
  * Introduced `should_stitch_this_side` condition to improve readability.
  * Explicitly handle both true exterior boundaries and self-stitching across
    registered disconnected boundary pairs.
@ChengHauYang
Copy link
Member Author

ChengHauYang commented Nov 7, 2025

Thanks, @roystgnr, for taking your time to review my changes! I’ve updated the implementation and clarified the comments. Could you give me some feedback if you are available? Thanks!
The function now explicitly handles only the disconnected boundary pairs registered within this mesh, while ignoring those defined in other_mesh. Cross-mesh disconnected-boundary stitching would not happen. (These details are now properly documented within the function comments.)
I revised the code and made the comments more understandable.
I hope this resolves the earlier confusion; thank you again for the helpful discussion!

Copy link
Member

@roystgnr roystgnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hate to bring up something huge and old on top of the issue in the new stitching support, but typing "disconnected boundary" over and over again in the midst of unrelated confusion has me wondering whether we can't come up with a better name to begin with.

Right now, if we create a slit mesh, then the boundaries on opposite sides of the slit are already topologically disconnected ... so with this PR, we can then call add_disconnected_boundaries to connect them, and we only refer to them as "disconnected boundaries" once they've got a connection added? It seems entirely backwards and I fear that's going to confuse users.

Got any better ideas? disjoint_neighbor_boundary_pairs, maybe? disjoint_neighbor_boundaries? Maybe the improvement of "disjoint" over "disconnected" relies on too narrow a view or too broad a background of topology here, but I think it's least a small improvement, and I definitely like getting "neighbor" in there since the principal effect of the setting is to establish neighbor links.


#ifdef LIBMESH_ENABLE_PERIODIC
if (account_for_disconnected_boundaries)
this->remove_disconnected_boundaries_pair(this_mesh_boundary_id, other_mesh_boundary_id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still wrong, though, if it's not copying disconnected boundary pairs from a distinct other_mesh to this. We need to libmesh_not_implemented_msg() in that case in the very least, but I don't think adding the copy (and a test for it, for that matter) would be hard. Ideally we'd want to sanity check as we go (if a and b also exist as boundary ids on this, we should be screaming and dying, not adding neighbor pointers between them) too.

Right now, it looks to me like, if we stitch other_mesh X with disconnected boundary pair a,b into this mesh Y!=X, then we just silently drop the PeriodicBoundary objects for a,b. We can't drop mesh features when we're stitching them.


#ifdef LIBMESH_ENABLE_PERIODIC
if (account_for_disconnected_boundaries)
this->remove_disconnected_boundaries_pair(this_mesh_boundary_id, other_mesh_boundary_id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A unit test here would probably only take 4 elements in a row - elements 1 and 2 with a disconnected boundary in between them, elements 3 and 4 likewise, then stitch the other side of 2 to the other side of 3, and make sure that both the 1-2 and the 3-4 pairing still exist afterward.

…dary pairs”; add cross-mesh copy, sanity checks, and regression coverage

This refactor replaces the legacy term “disconnected boundaries” with the
clearer and topologically consistent “disjoint neighbor boundary pairs.”
The new terminology explicitly represents paired but geometrically disjoint
neighbor surfaces.

Functional changes:
- API renames:
  * add_disconnected_boundaries() -> add_disjoint_neighbor_boundary_pairs()
  * get_disconnected_boundaries() -> get_disjoint_neighbor_boundary_pairs()
  * remove_disconnected_boundaries_pair() -> remove_disjoint_boundary_pair()
  * _disconnected_boundary_pairs -> _disjoint_boundary_pairs
- Enhanced stitching logic:
  * stitching_helper() now recognizes valid disjoint pairs defined on either mesh.
  * Added sanity/safety checks:
      - Raise libmesh_error_msg() if a/b are unpaired on one mesh but paired on the other.
      - Abort stitching if (a,b) pairs are mismatched within the same mesh.
  * Disjoint pair data (PeriodicBoundary objects) is copied across meshes;
    duplicates are skipped, mismatches raise errors.
- Refinement safety:
  * Refinement across disjoint neighbor pairs remains disabled until full
    support is implemented.

Testing:
- Replaced disconnected_neighbor_test.C -> disjoint_neighbor_test.C.
- Added regression test with four elements in a row to ensure stitching
  preserves all disjoint neighbor pairs and does not remove unrelated pairs.
- Added DisjointNeighborTest::testDisjointNeighborConflictError to verify
  correct handling of mismatched pair registration.
- All existing temperature-jump, stitching, and clone-equality tests pass.
@ChengHauYang
Copy link
Member Author

Hi @roystgnr,

Thanks for the feedback!! The newest two commits try to address your comments:

(a) Rename _disconnected_boundary_pairs to be _disjoint_neighbor_boundary_pairs for clarity. All related identifiers using "disconnected" have been updated to "disjoint."

(b) remove_disjoint_boundary_pair only removes the pair when we successfully stitch two disjoint neighbor boundaries together, so that they should not be considered as "disjoint boundary pair" anymore. I added two unit tests for this:
One is this mesh X has four disjoint elements (other mesh Y is nullptr). After stitching elem2 and elem3, we check whether the 1–2 and 3–4 pairings still exist.
The second one is that X has two disjoint elements and Y has two disjoint elements. After stitching elem2 and elem3, we check whether the 1–2 and 3–4 pairings still exist.

(c) Copy disjoint neighbor boundary pairs from other_mesh to this in stitching_helper. If (a,b) from other_mesh already exists on this, we would be screaming unless they already have PeriodicBoundary objects connecting them.

Could you help me review the newest commits if you are available? Thanks!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants